import { Sprite } from "@/sprites/Sprite.js";
import { AudioManager } from "@/managers/AudioManager.js";
import { BlendModes } from "@/utils/BlendModes.js";
import { ImageManager } from "@/managers/ImageManager";
export class Sprite_Animation extends Sprite {
    static _checker1 = new Map();
    static _checker2 = new Map();
    constructor() {
        super();
        this._reduceArtifacts = true;
        this.initMembers();
    }

    initMembers() {
        this._target = null;
        this._animation = null;
        this._mirror = false;
        this._delay = 0;
        this._rate = 4;
        this._duration = 0;
        this._flashColor = [0, 0, 0, 0];
        this._flashDuration = 0;
        this._screenFlashDuration = 0;
        this._hidingDuration = 0;
        this._source1 = null;
        this._source2 = null;
        this._AnimtaskCount=0;

        this._cellSprites = [];
        this._screenFlashSprite = null;
        this._duplicated = false;
        this.zIndex = 8;
    }

    setup(target, animation, mirror, delay) {
        this._target = target;
        this._animation = animation;
        this._mirror = mirror;
        this._delay = delay;
        if (this._animation) {
            //this.remove();
            this.setupRate();
            this.setupDuration();
            this.loadBitmaps();
            this.createSprites();
        }
    }

    remove() {
        if (this.parent && this.parent.removeChild(this)) {
            this._target.setBlendColor([0, 0, 0, 0]);
            this._target.show();
        }
        
    }

    setupRate() {
        this._rate = 4;
    }

    setupDuration() {
        this._duration = this._animation.frames.length * this._rate + 1;
    }

    update() {
        super.update();
        this.updateMain();
        this.updateFlash();
        this.updateScreenFlash();
        this.updateHiding();
        
    }

    updateFlash() {
        if (this._flashDuration > 0) {
            let d = this._flashDuration--;
            this._flashColor[3] *= (d - 1) / d;
            this._target.setBlendColor(this._flashColor);
        }
    }

    updateScreenFlash() {
        if (this._screenFlashDuration > 0) {
            let d = this._screenFlashDuration--;
            if (this._screenFlashSprite) {
                this._screenFlashSprite.x = -this.absoluteX();
                this._screenFlashSprite.y = -this.absoluteY();
                this._screenFlashSprite.opacity *= (d - 1) / d;
                this._screenFlashSprite.visible = (this._screenFlashDuration > 0);
            }
        }
    }

    absoluteX() {
        let x = 0;
        let object = this;
        while (object) {
            x += object.x;
            object = object.parent;
        }
        return x;
    }

    absoluteY() {
        let y = 0;
        let object = this;
        while (object) {
            y += object.y;
            object = object.parent;
        }
        return y;
    }

    updateHiding() {
        if (this._hidingDuration > 0) {
            this._hidingDuration--;
            if (this._hidingDuration === 0) {
                this._target.show();
            }
        }
    }

    isPlaying() {
        return this._duration > 0;
    }

    loadBitmaps() {
        let name1 = this._animation.animation1Name;
        let name2 = this._animation.animation2Name;
        // let hue1 = this._animation.animation1Hue;
        // let hue2 = this._animation.animation2Hue;
        this._AnimtaskCount+=2;
        ImageManager.loadAnimation(name1).then(source=>{
            --this._AnimtaskCount;
            this._source1=source;
        });
        ImageManager.loadAnimation(name2).then(source=>{
            --this._AnimtaskCount;
            this._source2=source;
        });
    }

    isReady() {
        return this._AnimtaskCount<=0;
    }

    createSprites() {
        if (!Sprite_Animation._checker2.get(this._animation)) {
            this.createCellSprites();
            if (this._animation.position === 3) {
                Sprite_Animation._checker2.set(this._animation,true);
            }
            this.createScreenFlashSprite();
        }
        if (Sprite_Animation._checker1.get(this._animation)) {
            this._duplicated = true;
        } else {
            this._duplicated = false;
            if (this._animation.position === 3) {
                Sprite_Animation._checker1.set(this._animation,true);
            }
        }
    }

    createCellSprites() {
        this._cellSprites = [];
        for (let i = 0; i < 16; i++) {
            let sprite = new Sprite();
            sprite.anchor.x = 0.5;
            sprite.anchor.y = 0.5;
            this._cellSprites.push(sprite);
            this.addChild(sprite);
        }
    }

    createScreenFlashSprite() {
        this._screenFlashSprite = new ScreenSprite();
        this.addChild(this._screenFlashSprite);
    }

    updateMain() {
        if (this.isPlaying() && this.isReady()) {
            if (this._delay > 0) {
                this._delay--;
            } else {
                this._duration--;
                this.updatePosition();
                if (this._duration % this._rate === 0) {
                    this.updateFrame();
                }
            }
        }
    }

    updatePosition() {
        if (this._animation.position === 3) {
            this.x = this.parent.width / 2;
            this.y = this.parent.height / 2;
        } else {
            let parent = this._target.parent;
            let grandparent = parent ? parent.parent : null;
            this.x = this._target.x;
            this.y = this._target.y;
            if (this.parent === grandparent) {
                this.x += parent.x;
                this.y += parent.y;
            }
            if (this._animation.position === 0) {
                this.y -= this._target.height;
            } else if (this._animation.position === 1) {
                this.y -= this._target.height / 2;
            }
        }
    }

    updateFrame() {
        if (this._duration > 0) {
            let frameIndex = this.currentFrameIndex();
            this.updateAllCellSprites(this._animation.frames[frameIndex]);
            this._animation.timings.forEach((timing)=>{
                if (timing.frame === frameIndex) {
                    this.processTimingData(timing);
                }
            });
        }
    }

    currentFrameIndex() {
        return (this._animation.frames.length -
                Math.floor((this._duration + this._rate - 1) / this._rate));
    }
//[[0,0,0,250,0,0,255,1],[-1,0,0,0,0,0,0,0],[-1,0,0,0,0,0,0,0],[-1,0,0,0,0,0,0,0]]
    updateAllCellSprites(frame) {
        for (let i = 0; i < this._cellSprites.length; i++) {
            let sprite = this._cellSprites[i];
            if (i < frame.length) {
                this.updateCellSprite(sprite, frame[i]);
            } else {
                sprite.visible = false;
            }
        }
    }
//[0,0,0,250,0,0,255,1]
    updateCellSprite(sprite, cell) {
        let pattern = cell[0];
        if (pattern >= 0) {
            let sx = pattern % 5 * 192;
            let sy = Math.floor(pattern % 100 / 5) * 192;
            let mirror = this._mirror;
            sprite.source = pattern < 100 ? this._source1 : this._source2;
            sprite.setFrame(sx, sy, 192, 192);
            sprite.x = cell[1];
            sprite.y = cell[2];
            sprite.rotation = cell[4] * Math.PI / 180;
            sprite.scale.x = cell[3] / 100;

            if(cell[5]){
                sprite.scale.x *= -1;
            }
            if(mirror){
                sprite.x *= -1;
                sprite.rotation *= -1;
                sprite.scale.x *= -1;
            }

            sprite.scale.y = cell[3] / 100;
            sprite.alpha = cell[6]/255;
            sprite.blendMode = BlendModes[cell[7]];
            sprite.visible = true;
        } else {
            sprite.visible = false;
        }
    }

    processTimingData(timing) {
        let duration = timing.flashDuration * this._rate;
        switch (timing.flashScope) {
        case 1:
            this.startFlash(timing.flashColor, duration);
            break;
        case 2:
            this.startScreenFlash(timing.flashColor, duration);
            break;
        case 3:
            this.startHiding(duration);
            break;
        }
        if (!this._duplicated && timing.se) {
            AudioManager.playSe(timing.se);
        }
    }

    startFlash(color, duration) {
        this._flashColor =[...color];
        this._flashDuration = duration;
    }

    startScreenFlash(color, duration) {
        this._screenFlashDuration = duration;
        if (this._screenFlashSprite) {
            this._screenFlashSprite.setColor(color[0], color[1], color[2]);
            this._screenFlashSprite.opacity = color[3];
        }
    }

    startHiding(duration) {
        this._hidingDuration = duration;
        this._target.hide();
    }
}